/**
 * 
 */
package org.hackystat.ui.hackerrific.client;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author David J. Nickles
 *
 */
public class EntryPanel extends HorizontalPanel implements FocusListener, ClickListener, 
  KeyboardListener {

  /** {@literal} QUESTION for the user. */  
  private static final String QUESTION = "What are you hacking?"; 
  /** {@literal} BLANKIMAGE icon. */        
  public static final String BLANKIMAGE = "images/blank.gif"; 
  /** {@literal} WAITIMAGE icon. */        
  public static final String WAITIMAGE = "images/wait-animated.gif"; 
  /** {@literal} USER_INVALID user invalid event state. */        
  private static final String USER_INVALID = "images/user-warning.gif"; 
  /** {@literal} USERTWITTERPAGEIMAGE icon. */        
  public static final String USERTWITTERPAGEIMAGE = "images/tweet.gif"; 
  /** {@literal} FAVORTEIMAGE icon. */        
  public static final String FAVORTEIMAGE = "images/favorite.gif"; 
  /** {@literal} INACTIVEIMAGE icon. */        
  public static final String INACTIVEIMAGE = "images/white-trans.gif"; 
  /** {@literal} ACTIVEIMAGE icon. */        
  public static final String ACTIVEIMAGE = "images/green-trans.gif"; 
  /** {@literal} HOMEIMAGE icon. */        
  public static final String HOMEIMAGE = "images/web.gif"; 
  /** {@literal} SETTINGSIMAGE icon. */        
  public static final String SETTINGSIMAGE = "images/info.gif"; 
  /** {@literal} POLLIMAGE icon. */        
  public static final String POLLIMAGE = "images/refresh.gif"; 
  /** {@literal} STATUSPANELSTYLE stylesheet class for labels. */  
  private static final String ENTRYPANELSTYLE = "entry";    
  /** {@literal} FNSTRIPSTYLE stylesheet class for examples. */  
  private static final String FNSTRIPSTYLE = "fnstrip";  
  /** {@literal} TWITTERURL the main twitter url. */  
  private static final String TWITTERURL = "http://twitter.com/";  
  /** {@literal} NEWPAGE directive to open page in a new browser window. */  
  private static final String NEWPAGE = "_blank";  
  /** {@literal} PAGEFEATURES features of new browser window. */  
  private static final String PAGEFEATURES = "";  
  /** {@literal} PRCERRORNAME name for RPC errors. */  
  private static final String PRCERRORNAME = "Error on Update RPC"; 

  private Image homeImage;
  private Image settingsImage;
  private Image pollImage;
  private TextArea entryArea;
  private Boolean rpcOpen;
  private StatusesPanel statusesPanel;
  
  /**
   * Create a new tweet submission panel.
   * 
   * @param statusesPanel the paired statuses panel
   */
  public EntryPanel(StatusesPanel statusesPanel) {
    this.statusesPanel = statusesPanel;
    this.rpcOpen = Boolean.TRUE;
    setStyleName(ENTRYPANELSTYLE);
    VerticalPanel functionstrip = new VerticalPanel();
    functionstrip.setStyleName(FNSTRIPSTYLE);
    functionstrip.add(this.homeImage = new Image(USERTWITTERPAGEIMAGE));
    this.homeImage.setTitle("Visit your page at Twitter.");
    this.homeImage.setPixelSize(20, 20);
    this.homeImage.addClickListener(this);
    functionstrip.add(this.settingsImage = new Image(SETTINGSIMAGE));
    this.settingsImage.setTitle("Configure Hackerrific.");
    this.settingsImage.setPixelSize(20, 20);
    functionstrip.add(this.pollImage = new Image(POLLIMAGE));
    this.pollImage.setTitle("Poll for tweets.");
    this.pollImage.setPixelSize(20, 20);
    this.pollImage.addClickListener(this);
    add(functionstrip);
    add(this.entryArea = new TextArea());
    this.entryArea.setPixelSize(200, 69);
    this.entryArea.setText(QUESTION);
    this.entryArea.setTitle(QUESTION);
    this.entryArea.addKeyboardListener(this);
    this.entryArea.addFocusListener(this);
  }
  
  /**
   * Returns a reference to the 'Settings' image which closes this panel.
   * 
   * @return the UI item for flipping to the settings panel.
   */
  public Image getOkImage() {
    return this.settingsImage;
  }

  /**
   * Respond to Widgets gaining focus.
   * @param sender the Widget that lost focus
   */
  public void onFocus(Widget sender) {
    if (this.entryArea.getText().equals(QUESTION)) {
      this.entryArea.setText("");
    }
  }
  
  /**
   * Respond to Widgets losing focus.
   * @param sender the Widget that lost focus
   */
  public void onLostFocus(Widget sender) {
    if (this.entryArea.getText() == "") {
      this.entryArea.setText(QUESTION);
    }
  }

  /**
   * Respond to Widgets that are clicked on.
   * @param sender the Widget that was clicked
   */
  public void onClick(Widget sender) {
    if (sender.equals(this.homeImage)) {
      String userCookie = Cookies.getCookie("user");
      if (userCookie == null) {
        userCookie = "NoUserCookie";
      }
      Window.open(TWITTERURL + userCookie, NEWPAGE, PAGEFEATURES);
    }
    else if (sender.equals(this.pollImage)) {
      this.statusesPanel.poll();
    }
  }

  /**
   * Fired when the user depresses a physical key.
   *
   * @param sender the widget that was focused when the event occurred.
   * @param keyCode the physical key that was depressed. Constants for this
   *          value are defined in this interface with the KEY prefix.
   * @param modifiers the modifier keys pressed at when the event occurred.
   */
  public void onKeyDown(Widget sender, char keyCode, int modifiers) {
    // TODO Auto-generated method stub
    
  }

  /**
   * Fired when a keyboard action generates a character. This occurs after
   * onKeyDown and onKeyUp are fired for the physical key that was pressed.
   *
   * <p>
   * It should be noted that many browsers do not generate keypress events
   * for non-printing keyCode values, such as {@link KeyboardListener#KEY_ENTER}
   * or arrow keys.  These keyCodes can be reliably captured either with
   * {@link KeyboardListener#onKeyDown(Widget, char, int)} or
   * {@link KeyboardListener#onKeyUp(Widget, char, int)}.
   * </p>
   *
   * @param sender the widget that was focused when the event occurred.
   * @param keyCode the Unicode character that was generated by the keyboard
   *          action.
   * @param modifiers the modifier keys pressed at when the event occurred.
   */
  public void onKeyPress(Widget sender, char keyCode, int modifiers) {
    // TODO Auto-generated method stub
    
  }

  /**
   * This method checks to see if the user pressed the ENTER key while typing in the input text
   * area, and if so, then sends this text as a Status to the Twitter server.
   *
   * @param sender the widget that was focused when the event occurred.
   * @param keyCode the physical key that was released. Constants for this value
   *          are defined in this interface with the KEY prefix.
   * @param modifiers the modifier keys pressed at when the event occurred.
   */
  public void onKeyUp(Widget sender, char keyCode, int modifiers) {
    if ((sender.equals(this.entryArea)) && (keyCode == KeyboardListener.KEY_ENTER)) {
      startRpc(this.entryArea.getText());
      this.entryArea.setText(QUESTION);
    } 
  }
  
  /**
   * This is the callback method for the Timer task. This method polls the servlet 
   * (which communicates with the Twitter server).
   * @param message the tweet text
   */
  public void startRpc(String message) {
    if (this.rpcOpen.booleanValue()) {
      this.rpcOpen = Boolean.FALSE;
      this.homeImage.setUrl(WAITIMAGE);
      String userCookie = Cookies.getCookie("user");
      if (userCookie == null) {
        userCookie = "NoUserCookie";
      }
      String passwordCookie = Cookies.getCookie("password");
      if (passwordCookie == null) {
        passwordCookie = "NoPasswordCookie";
      }
      rpcUpdate(userCookie, passwordCookie, message);
    }
  }

  /**
   * This method handles the response from the RPC call.
   */
  public void finishRpc() {
    this.homeImage.setUrl(USERTWITTERPAGEIMAGE);
    this.rpcOpen = Boolean.TRUE;
  }

  /**
   * This method performs an asynchronous remote call out to the sensor data viewer service
   * for particular sensor data over a specified period as indicated in the URI.
   * @param user for authentication
   * @param password for authentication
   * @param message the text of the tweet
   */ 
  public void rpcUpdate(String user, String password, String message) { 
    RPCServiceFactory.getInstance().getService().update(user, password, message,
      new AsyncCallback()
      {
        public void onSuccess(Object result) {
          finishRpc();
        }

        public void onFailure(Throwable caught) {
          if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
            log(PRCERRORNAME, "Cannot invoke method on servlet.");
          } 
          else {
            log(PRCERRORNAME, caught.toString());
          }
        }
      });
  }
  
  /**
   * Log this message in the display.
   * @param header the message header or subject
   * @param body the message body
   */
  public void log(String header, String body) {
    this.pollImage.setUrl(USER_INVALID);
    this.entryArea.setText(header + " : " + body);
  }
}
